# -*- coding: utf-8 -*-
import time
import requests
from   requests_html import HTMLSession
import json
import os
import sys
import glob
import datetime
import threadpool
import base64
import db

class Organization:
    def __init__(self,site,user,token):
        self.site = site
        self.user = user
        self.token = token

    def getBasicAuth(self):
        return "Basic {}".format(base64.b64encode((self.user +":"+ self.token).encode('utf-8')).decode())

class Crawler:
    def __init__(self,organization,data_path="./data",session_id = None):
        self.organization = organization
        self.session = HTMLSession()
        if session_id:
            self.session.cookies["JSESSIONID"] = session_id
        else:
            self.session.headers.update({"Authorization":self.organization.getBasicAuth()})
        self.data_path = data_path

    def getResource(self,url,resourceName):
        page,recordsPerPage = 0, 50
        data = []
        while True:
            query = self.organization.site + url + "&startAt={}&maxResults={}".format(recordsPerPage*page,recordsPerPage)
            print(query)
            response = self.session.get(url = query)
            if response.status_code > 300:
                print("Error {} to open {}".format(response.status_code,query))
                break
            ret = response.json()
            data = data + ret[resourceName]
            page = page + 1
            if(len(ret[resourceName]) < recordsPerPage):
                break
        return data
    
    def query(self,url, path = None):
        url = "{}{}".format(self.organization.site,url)
        # print("get {} ...".format(url))
        try:
            response = self.session.get(url)
            if response.status_code > 300:
                print("Error: get {} response.status_code = {}".format(url,response.status_code))
                return None
            data = response.json()
            if path:
                with open(path,'w', encoding='utf8') as file:
                    json.dump(data, file)
            return data
        except Exception as ex:
            print(ex)

    def getProjects(self):
        data = self.query("/rest/api/2/project")
        if data is None:
            return
        for i in data:
            self.getProjectDetail(i)
            issues = self.query("/rest/api/2/search?jql=project={}&startAt=0&maxResults=1".format(i["id"]))
            if issues is None:
                continue
            print("read project {} issues {}".format(i["key"],issues["total"]))
            i["total"] = issues["total"]            
            if i["total"] > 0:
                i["updated"] = issues["issues"][0]["fields"]["updated"]
        with open("{}/projects.json".format(self.data_path),'w', encoding='utf8') as file:
            json.dump(data, file)
        return data
        # return list(map(lambda i: db.Project(id = i["id"], name = i["name"], project_key = i["key"]),data))

    def getProjectDetail(self,project):
        self.query("/rest/api/2/project/{}".format(project["id"]),
                    "{}/{}_detail.json".format(self.data_path,project["key"]))
        self.query("/rest/api/2/project/{}/statuses".format(project["id"]),
                    "{}/{}_statuses.json".format(self.data_path,project["key"]))
        self.query("/rest/api/2/project/{}/versions".format(project["id"]),
                    "{}/{}_versions.json".format(self.data_path,project["key"]))
        self.query("/rest/projectconfig/1/workflowscheme/{}".format(project["key"]),
                    "{}/{}_workflowscheme.json".format(self.data_path,project["key"]))

    def getProjectIssuesCount(self,project):
        return self.query("/rest/api/2/search?jql=project={}&startAt=0&maxResults=1".format(project))

    def getProjectIssueKeys(self,project,days):
        if days is None:
            url = "/rest/api/2/search?jql=project='{}'&fields=changelog".format(project)
        else:
            url = "/rest/api/2/search?jql=project='{}' and updated>=-{}d&fields=changelog".format(project,days)
        data = self.getResource(url,"issues")
        return [i["key"] for i in data]

    def getChangelog(self,issue):
        # /rest/api/2/issue/10000
        self.query("/rest/agile/1.0/issue/{}?expand=changelog".format(issue),
            "{}/{}/{}.json".format(self.data_path,self.name,issue)
            )

    def getProjectIssues(self,project,days):
        self.name = project
        print("read issues information from {}".format(project))
        keys = self.getProjectIssueKeys(project,days)
        print("total {} issues. downloading...".format(len(keys)))
        sys.stdout.flush()
        directory = "{}/{}".format(self.data_path,project)
        if not os.path.exists(directory):
            os.makedirs(directory) 
        pool = threadpool.ThreadPool(20)
        start_time = time.time()
        requests = threadpool.makeRequests(self.getChangelog,keys)
        [pool.putRequest(req) for req in requests]
        pool.wait()
        end_time = time.time()
        print("%s seconds used, good luck" % (end_time - start_time))

    def getWorkflowSchema(self,project):
        return self.query("/rest/projectconfig/1/workflowscheme/{}".format(project))

    def getWorkflow(self,schema):
        workflow = self.query("/rest/api/2/workflowscheme/{}/workflow".format(schema))
        for i in workflow:
            i["steps"] = self.query("/rest/projectconfig/1/workflow?workflowName={}".format(i["workflow"]))["sources"]
        return workflow